#include "ZsetObject.hpp"
#include "../Tool.hpp"
#include "../../base/Defind.hpp"

inline auto split_command_value(std::string& command, std::string& v1, std::string& v2) -> void
{
    std::string &tmp = v1;
    // initialize the key and value
    for (char c : command)
    {
        if (c == ' ')
        {
            tmp = v2;
            continue;
        }
        tmp += c;
    }
}

using namespace DBServer::Database;
using CallBack = std::function<void(ZsetObject&, CommandRequest&&, CommandRespond&)>;

void ZsetObject::command_excute(CommandRespond& crp, CommandRequest&& crq, com_func_t& cft) 
{
    (cb_table[cft.second])(*this, std::move(crq), crp);
}

std::unordered_map<int, CallBack> ZsetObject::cb_table([]{

    std::unordered_map<int, CallBack> temp;
    temp[COMMAND_GET] = [](ZsetObject& zo, CommandRequest&& crq, CommandRespond& crp){
        crp.respond = Translator::vector_to_string_1(zo.get());
    };
    
    temp[COMMAND_ZADD] = [](ZsetObject& zo, CommandRequest&& crq, CommandRespond& crp){
        std::string score{""};
        std::string data{""};
        // initialize the key and value
        split_command_value(crq.command[COMMAND_VALUE], score, data);
        
        double _score = 0.0;
        bool is_legal = Translator::string_to_double(std::move(score), _score);
        if (!is_legal)
        {
            crp.respond = ZSETOBJECT_INPUT_ILLEGAL;
            return;
        }

        auto ret = zo.zadd(_score, std::move(data));

        if (ret)
        {
            crp.respond = OK;
        }
        else
        {
            crp.respond = ZSETOBJECT_ZADD_DEFAULT;
        }
    };
    temp[COMMAND_ZLEN] = [](ZsetObject& zo, CommandRequest&& crq, CommandRespond& crp){
        auto ret = zo.zlen();
        crp.respond = Translator::int_to_string(ret);
    };
    
    temp[COMMAND_ZCOUNT] = [](ZsetObject& zo, CommandRequest&& crq, CommandRespond& crp){
        std::string range_1{""};
        std::string range_2{""};
        // initialize the key and value
        split_command_value(crq.command[COMMAND_VALUE], range_1, range_2);

        int range_int_1 = Translator::string_to_int(range_1);
        int range_int_2 = Translator::string_to_int(range_2);
        auto ret = zo.zcount(range_int_1, range_int_2);

        crp.respond = Translator::int_to_string(ret);
    };
    
    temp[COMMAND_ZRANK] = [](ZsetObject& zo, CommandRequest&& crq, CommandRespond& crp){
        std::string _score{""};
        std::string data{""};
        // initialize the key and value
        split_command_value(crq.command[COMMAND_VALUE], _score, data);

        double score;
        auto is_illegal = Translator::string_to_double(std::move(_score), score);
        if (!is_illegal)
        {
            crp.respond = ZSETOBJECT_INPUT_ILLEGAL;
            return;
        }

        auto ret = zo.zrank(score, std::move(data));

        if (ret == -1)
        {
            crp.respond = ZSETOBJECT_ZRAND_DEFAULT;
        } else
        {
            crp.respond = Translator::int_to_string(ret);
        }
    };
    
    temp[COMMAND_ZSCORE] = [](ZsetObject& zo, CommandRequest&& crq, CommandRespond& crp){
        std::string data;
        double score;
        auto is_illegal = Translator::string_to_double(std::move(crq.command[COMMAND_VALUE]), score);
        if (!is_illegal)
        {
            crp.respond = ZSETOBJECT_INPUT_ILLEGAL;
            return;
        }

        auto ret = zo.zscore(score, data);

        if (!ret)
        {
            crp.respond = ZSETOBJECT_ZSCORE_DEFAULT;
        }
    };
    
    temp[COMMAND_ZREMOVE] = [](ZsetObject& zo, CommandRequest&& crq, CommandRespond& crp){
        std::string data;
        double score;
        auto is_illegal = Translator::string_to_double(std::move(crq.command[COMMAND_VALUE]), score);
        if (!is_illegal)
        {
            crp.respond = ZSETOBJECT_INPUT_ILLEGAL;
            return;
        }
        auto ret = zo.zremove(score, data);

        if (!ret)
        {
            crp.respond = ZSETOBJECT_ZREMOVE_DEFAULT;
        }
    };

    return temp;
}());